# Visualización de datos geográficos con leaflet
En esta sesión aprenderemos a utilizar leaflet (opens new window) en nuestros notebooks de python. Es posible también integrar esta librería en R, pero hoy nos limitaremos a python.
La librería que nos ayudará a enlazar python y leaflet será folium, que como veremos es muy cómoda de utilizar.
# Configuración
En primer lugar, actualizaremos folium a la última versión, para conseguir todas las funcionalidades.
!pip install folium==0.12.0
# Visualización de mapas con folium (leaflet)
Importamos las dependencias
import folium
import json
Comenzamos creando un mapa muy simple con un marcador en las coordenadas [40.4066853,-3.7091432]. El parámetro popup permite mostrar información cuando se hace click encima del marcador en el mapa.
myloc = [40.4066853,-3.7091432]
m = folium.Map(location = myloc, zoom_start=15)
folium.Marker(myloc, popup='Estás aquí').add_to(m)
m
De hecho, popup admite texto con etiquetas <HTML/>
m = folium.Map(location = myloc, zoom_start=15)
folium.Marker(myloc, popup='<p>Tu IP dice <h4>estás aquí<h4/><p/>').add_to(m)
m
Podemos añadir tantos marcadores como necesitemos y cambiar otras propiedades.
folium.Marker(location=[40.42,-3.72], tooltip='pero en realidad estás aquí').add_to(m)
m
Ahora descargaremos el mapa de países de europa en formato GeoJson. Podemos configurar nuestro propio mapa en este sitio: https://geojson-maps.ash.ms/
!cd data/ && wget 'https://raw.githubusercontent.com/jlaria/bigdata5/main/data/custom.geo.json'
Con folium.GeoJson podemos mostrar directamente información de un archivo en formato .geo.json.
m = folium.Map()
folium.GeoJson('data/custom.geo.json').add_to(m)
m
Podemos seguir configurando nuestro mapa.
m = folium.Map()
folium.GeoJson('data/custom.geo.json',
style_function = lambda x: {'fillOpacity': '0', 'weight': '1'}).add_to(m)
m
Para comprender la estructura de custom.geo.json vamos a traerlo a python.
countries = json.load(open('data/custom.geo.json'))
countries.keys()
countries['type']
countries['features'][0]
Vemos que el campo properties tiene mucha información relacionada con el país, y podemos añadir nuestra propia información. Vamos a utilizar esta información para mostrar un tooltip sobre cada país. Para mostrar colores podemos escoger un tema aquí (opens new window).
m = folium.Map()
colors = ['#8c510a', '#bf812d', '#dfc27d', '#f6e8c3', '#f5f5f5', '#c7eae5', '#80cdc1', '#35978f', '#01665e']
folium.GeoJson('data/custom.geo.json',
style_function = lambda x: {
'fillColor': colors[int(x['properties']['mapcolor9'])-1],
'fillOpacity': '0.8',
'weight': '1'},
tooltip = folium.GeoJsonTooltip(
fields = ['admin', 'formal_en', 'income_grp']
)
).add_to(m)
m
También podemos asignar los colores en función de una variable continua, por ejemplo, gdp_md_est. Para esto, primeramente vamos a explorar el rango de esta variable, en un data frame de pandas.
import pandas as pd
pdf = None
for i in range(len(countries['features'])):
pdf = pd.DataFrame(countries['features'][i]['properties'], index=[i]).append(pdf)
pdf
pdf[['admin', 'gdp_md_est']].sort_values('gdp_md_est')
Creamos una escala lineal desde 0 hasta 3
import branca.colormap as cmp
linear = cmp.LinearColormap(
['red', 'yellow', 'green'],
vmin=0, vmax=3,
caption='GDP (millones)' #Caption for Color scale or Legend
)
linear
m = folium.Map()
folium.GeoJson('data/custom.geo.json',
style_function = lambda x: {
'fillColor': linear(x['properties']['gdp_md_est']/1e+6),
'fillOpacity': '0.8',
'weight': '1'},
tooltip = folium.GeoJsonTooltip(
fields = ['admin', 'formal_en', 'income_grp']
)
).add_to(m)
linear.add_to(m)
m
Ahora vamos a escalar por el tamaño de la población.
pdf.loc[:,'gdp_per_capita'] = pdf.gdp_md_est/pdf.pop_est
pdf[['admin', 'gdp_md_est', 'pop_est', 'gdp_per_capita']].sort_values('gdp_per_capita')
| admin | gdp_md_est | pop_est | gdp_per_capita | |
|---|---|---|---|---|
| 35 | Moldova | 10670.0 | 4320748 | 0.002469 |
| 25 | Kosovo | 5352.0 | 1804838 | 0.002965 |
| 3 | Albania | 21810.0 | 3639453 | 0.005993 |
| 7 | Bosnia and Herzegovina | 29700.0 | 4613414 | 0.006438 |
| 49 | Ukraine | 339800.0 | 45700395 | 0.007435 |
| 33 | Macedonia | 18780.0 | 2066718 | 0.009087 |
| 38 | Montenegro | 6816.0 | 672180 | 0.010140 |
| 45 | Republic of Serbia | 80340.0 | 7379339 | 0.010887 |
| 8 | Belarus | 114100.0 | 9648533 | 0.011826 |
| 41 | Romania | 271400.0 | 22215421 | 0.012217 |
| 0 | Bulgaria | 93750.0 | 7204687 | 0.013012 |
| 36 | Russia | 2266000.0 | 140041247 | 0.016181 |
| 39 | Poland | 667900.0 | 38482919 | 0.017356 |
| 31 | Latvia | 38860.0 | 2231503 | 0.017414 |
| 29 | Lithuania | 63330.0 | 3555179 | 0.017813 |
| 20 | Croatia | 82390.0 | 4489409 | 0.018352 |
| 43 | Portugal | 208627.0 | 10707924 | 0.019483 |
| 22 | Hungary | 196600.0 | 9905596 | 0.019847 |
| 12 | Faroe Islands | 1000.0 | 48856 | 0.020468 |
| 13 | Estonia | 27410.0 | 1299371 | 0.021095 |
| 40 | Slovakia | 119500.0 | 5463046 | 0.021874 |
| 34 | Malta | 9962.0 | 405165 | 0.024588 |
| 5 | Czech Republic | 265200.0 | 10211904 | 0.025970 |
| 46 | Slovenia | 59340.0 | 2005692 | 0.029586 |
| 32 | Monaco | 976.3 | 32965 | 0.029616 |
| 28 | Italy | 1823000.0 | 58126212 | 0.031363 |
| 18 | United Kingdom | 1977704.0 | 62262000 | 0.031764 |
| 19 | Greece | 343000.0 | 10737428 | 0.031944 |
| 17 | France | 2128000.0 | 64057792 | 0.033220 |
| 16 | Spain | 1403000.0 | 40525002 | 0.034621 |
| 10 | Germany | 2918000.0 | 82329758 | 0.035443 |
| 23 | Isle of Man | 2719.0 | 76512 | 0.035537 |
| 15 | Finland | 193500.0 | 5250275 | 0.036855 |
| 11 | Denmark | 203600.0 | 5500510 | 0.037015 |
| 4 | Belgium | 389300.0 | 10414336 | 0.037381 |
| 47 | Sweden | 344300.0 | 9059651 | 0.038004 |
| 14 | Guernsey | 2742.0 | 68633 | 0.039952 |
| 1 | Austria | 329500.0 | 8210281 | 0.040133 |
| 37 | Netherlands | 672000.0 | 16715999 | 0.040201 |
| 27 | Iceland | 12710.0 | 306694 | 0.041442 |
| 9 | Switzerland | 316700.0 | 7604467 | 0.041647 |
| 2 | Andorra | 3660.0 | 83888 | 0.043630 |
| 21 | Ireland | 188400.0 | 4203200 | 0.044823 |
| 44 | San Marino | 1662.0 | 30324 | 0.054808 |
| 26 | Jersey | 5100.0 | 91626 | 0.055661 |
| 6 | Aland | 1563.0 | 27153 | 0.057563 |
| 42 | Norway | 276400.0 | 4676305 | 0.059106 |
| 30 | Luxembourg | 39370.0 | 491775 | 0.080057 |
| 24 | Liechtenstein | 4160.0 | 34761 | 0.119674 |
| 48 | Vatican | 355.0 | 832 | 0.426683 |
for i in range(len(countries['features'])):
gdp = countries['features'][i]['properties']['gdp_md_est']
pop = countries['features'][i]['properties']['pop_est']
countries['features'][i]['properties']['gdp_per_capita'] = gdp/pop
# countries['features'][0]['properties']
linear = cmp.LinearColormap(
['red', 'yellow', 'green'],
vmin=0, vmax=0.1,
caption='GDP (scaled)' #Caption for Color scale or Legend
)
m = folium.Map()
folium.GeoJson(countries,
style_function = lambda x: {
'fillColor': linear(x['properties']['gdp_per_capita']),
'fillOpacity': '0.8',
'weight': '1'},
tooltip = folium.GeoJsonTooltip(
fields = ['admin', 'formal_en', 'income_grp', 'gdp_per_capita']
)
).add_to(m)
linear.add_to(m)
m
# Ejercicio
La tabla consumption.csv contiene la información del consumo eléctrico de varios países europeos. ¿Serías capaz de mostrar esta información en un mapa sobre los países, con una escala de colores que haga referencia al consumo anual de cada país?